package com.csizg.facemodel.view;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import com.csizg.facemodel.R;
import com.csizg.facemodel.tracker.DetectionBasedTracker;
import com.csizg.facemodel.util.CompareResult;
import com.csizg.facemodel.util.FaceUtil;
import com.csizg.facemodel.util.RawUtil;
import java.io.File;
import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.JavaCameraView;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;

/**
 * 横屏识别 图片对比方案
 *
 * @author haohao(ronghao3508@gmail.com) on 2018/5/7 17:51
 * @version v1.0
 */
public class MyHCameraView extends JavaCameraView
        implements CameraBridgeViewBase.CvCameraViewListener2 {

    public static final Scalar FACE_RECT_COLOR = new Scalar(0, 255, 0, 255);
    public static final int JAVA_DETECTOR = 0;
    public static final int NATIVE_DETECTOR = 1;
    public static final String TAG = "MyHCameraView";

    private static final String FACE1 = "face1";
    private static final String FACE2 = "currentface";
    public int mDetectorType = NATIVE_DETECTOR;
    public float mRelativeFaceSize = 0.1f;
    public int mAbsoluteFaceSize = 0;
    public CascadeClassifier mJavaDetector;
    public DetectionBasedTracker mNativeDetector;
    private Mat mRgba;
    private Mat mGray;
    private ICompareListener iCompareListener;
    private File mCascadeFile;
    private boolean captureFace;
    private boolean compareFace;

    public MyHCameraView(Context context, int cameraId) {
        super(context, cameraId);
        init();
    }

    public MyHCameraView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        setCvCameraViewListener(this);
        disableView();
        setCameraIndex(CAMERA_ID_FRONT);
        setMinFaceSize(0.1f);
        enableView();
    }

    public void switchCamera() {
        disableView();
        setCameraIndex(mCameraIndex == CAMERA_ID_BACK ? CAMERA_ID_FRONT : CAMERA_ID_BACK);
        setMinFaceSize(0.1f);
        enableView();
    }

    @Override
    public void onCameraViewStarted(int width, int height) {
        mGray = new Mat();
        mRgba = new Mat();

        mCascadeFile = RawUtil.getRawFile(getContext(), R.raw.lbpcascade_frontalface);
        setCascadeFile(mCascadeFile);
        mCascadeFile.delete();
    }

    @Override
    public void onCameraViewStopped() {
        mGray.release();
        mRgba.release();
    }

    @Override
    public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
        mRgba = inputFrame.rgba();
        mGray = inputFrame.gray();

        if (mAbsoluteFaceSize == 0) {
            int height = mGray.rows();
            if (Math.round(height * mRelativeFaceSize) > 0) {
                mAbsoluteFaceSize = Math.round(height * mRelativeFaceSize);
            }
            mNativeDetector.setMinFaceSize(mAbsoluteFaceSize);
        }

        MatOfRect faces = new MatOfRect();
        if (mDetectorType == JAVA_DETECTOR) {
            if (mJavaDetector != null) {
                mJavaDetector.detectMultiScale(mGray, faces, 1.1, 2, 2,
                        // TODO: objdetect.CV_HAAR_SCALE_IMAGE
                        new Size(mAbsoluteFaceSize, mAbsoluteFaceSize), new Size());
            }
        } else if (mDetectorType == NATIVE_DETECTOR) {
            if (mNativeDetector != null) mNativeDetector.detect(mGray, faces);
        } else {
            Log.e(TAG, "Detection method is not selected!");
        }

        Rect[] facesArray = faces.toArray();
        for (int i = 0; i < facesArray.length; i++) {
            Imgproc.rectangle(mRgba, facesArray[i].tl(), facesArray[i].br(), FACE_RECT_COLOR, 3);
            onFace(mRgba, facesArray[i]);
        }

        return mRgba;
    }

    public void setMinFaceSize(float faceSize) {
        mRelativeFaceSize = faceSize;
        mAbsoluteFaceSize = 0;
    }

    public void setCascadeFile(File mCascadeFile) {
        mNativeDetector = new DetectionBasedTracker(mCascadeFile.getAbsolutePath(), 0);
    }

    public void setCaptureFace() {
        captureFace = true;
    }

    public void setCompareFace() {
        compareFace = true;
    }

    public void onFace(Mat mat, Rect rect) {
        if (captureFace) {
            // 保存人脸信息
            final boolean isFinish = FaceUtil.saveImage(getContext(), mat, rect, FACE1);
            if (iCompareListener != null) {

                post(new Runnable() {
                    @Override
                    public void run() {
                        if (iCompareListener != null) {
                            iCompareListener.onCapture(isFinish);
                        }
                    }
                });
            }
            captureFace = false;
        }

        if (compareFace) {
            //对比
            if (iCompareListener != null) {
                FaceUtil.saveImage(getContext(), mat, rect, FACE2);
                final CompareResult cmp = FaceUtil.compareForFiles(getContext(), FACE2, 85);
                post(new Runnable() {
                    @Override
                    public void run() {
                        if (iCompareListener != null) {
                            iCompareListener.onCompare(cmp);
                        }
                    }
                });
            }

            compareFace = false;
        }
    }

    public void setICompareListener(ICompareListener iCompareListener) {
        this.iCompareListener = iCompareListener;
    }
}
